package org.flexharmony.harmonizer.javadef;

import static org.flexharmony.harmonizer.utils.CommonMethods.*;

import org.flexharmony.ASAcces;
import org.flexharmony.ASField;
import org.flexharmony.ASFieldType;
import org.flexharmony.ASTransient;
import org.flexharmony.ASVisiblity;
import org.objectweb.asm.AnnotationVisitor;
import org.objectweb.asm.Attribute;
import org.objectweb.asm.FieldVisitor;
import org.objectweb.asm.Opcodes;

/**
 * Converts the ASM field bytecode representation into a {@link JavaFieldDefinition}.
 * 
 * @author Corey Baswell
 */
public class JavaFieldVisitor implements FieldVisitor, AnnotationVisitor
{
  private String fieldName;

  /**
   * Does this field have an {@link ASTransient} annotation.
   */
  private boolean hasASTransientAnnotation;

  /**
   * If an {@link ASField} annotation is on this field its values will
   * be captured here.
   */
  private ASFieldImpl asField;
  
  private boolean fieldIsStatic;
  
  private boolean fieldIsFinal;
  
  private JavaVisibility fieldVisiblity;
  
  private JavaType fieldType;
  
  private Object fieldInitializationValue;
  
  private JavaFieldDefinition fieldDefinition;
  
  public JavaFieldVisitor(int fieldAccess, String fieldName, String fieldType, Object javaInitialValue)
  {
    fieldIsStatic = ((fieldAccess & Opcodes.ACC_STATIC) != 0);
    fieldIsFinal = ((fieldAccess & Opcodes.ACC_FINAL) != 0);
    fieldVisiblity = getVisiblity(fieldAccess);
    fieldInitializationValue = javaInitialValue;
    this.fieldName = fieldName;
    this.fieldType = new JavaType(fieldType);
  }
  
  /**
   * 
   * @return The converted field definition from the bytecode representation.
   */
  public JavaFieldDefinition getFieldDefinition()
  {
    return fieldDefinition;
  }
  
  /**
   * @see FieldVisitor#visitAnnotation(String, boolean)
   */
  public AnnotationVisitor visitAnnotation(String desc, boolean visible)
  {
    String name = convertByteCodeTypeName(desc);
    if (ASTransient.class.getCanonicalName().equals(name))
    {
      hasASTransientAnnotation = true;
      return null;
    }
    else if (ASField.class.getCanonicalName().equals(name))
    {
      asField = new ASFieldImpl();
      return this;
    }
    else
    {
      return null;
    }
  }

  /**
   * @see FieldVisitor#visitEnd()
   */
  public void visitEnd()
  {
    fieldDefinition = new JavaFieldDefinition(fieldName, hasASTransientAnnotation, asField, 
        fieldInitializationValue, fieldIsStatic, fieldIsFinal, fieldType, fieldVisiblity);
  }

  /**
   * @see FieldVisitor#visitAttribute(Attribute)
   */
  public void visitAttribute(Attribute attr)
  {}

  /**
   * @see AnnotationVisitor#visit(String, Object)
   */
  public void visit(String name, Object value)
  {
    if (name.equals("initialization"))
    {
      asField.initialization = value.toString();
    }
  }

  /**
   * @see AnnotationVisitor#visitEnum(String, String, String)
   */
  public void visitEnum(String name, String desc, String value)
  {
    if (name.equals("type"))
    {
      asField.type = ASFieldType.valueOf(value);
    }
    else if (name.equals("visiblity"))
    {
      asField.visibility = ASVisiblity.valueOf(value);
    }
    else if (name.equals("access"))
    {
      asField.access = ASAcces.valueOf(value);
    }
    else if (name.equals("propertyVisiblity"))
    {
      asField.propertyVisiblity = ASVisiblity.valueOf(value);
    }
  }

  /**
   * @see AnnotationVisitor#visitAnnotation(String, String)
   */
  public AnnotationVisitor visitAnnotation(String name, String desc)
  {
    return null;
  }

  /**
   * @see AnnotationVisitor#visitArray(String)
   */
  public AnnotationVisitor visitArray(String name)
  {
    return null;
  }
}
